
#include "stdafx.h"
#include "FontFactory.h"
#include "DPIForm.h"

CFontFactory::CFontFactory() 
	:m_FontNum(0), m_Font(nullptr), m_lastFont(nullptr), m_MarkNum(0), m_Mark(nullptr)
{
}

CFontFactory::~CFontFactory()
{
	if (m_Font)
	{
		for (intptr_t i = 0; i < m_FontNum; i++) if (m_Font[i]) ::DeleteObject(m_Font[i]);
		HeapFree(GetProcessHeap(), 0, m_Font);
	}
	if (m_Mark) HeapFree(GetProcessHeap(), 0, m_Mark);
}

CFontFactory* CFontFactory::Create(LPCWSTR fontName, intptr_t nHeight, intptr_t nWidth, intptr_t fnWeight)
{
	return Add(::CreateFont(CDPIForm::DPIY((int)nHeight), CDPIForm::DPIX((int)nWidth), 0, 0, (int)fnWeight,
		false, false, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, fontName));
}

CFontFactory* CFontFactory::CreateUnDPI(LPCWSTR fontName, intptr_t nHeight, intptr_t nWidth, intptr_t fnWeight)
{
	return Add(::CreateFont((int)nHeight, (int)nWidth, 0, 0, (int)fnWeight,
		false, false, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, fontName));
}

CFontFactory* CFontFactory::Create(intptr_t nPointSize, LPCWSTR lpszFaceName)
{
	CFont ft; ft.CreatePointFont((int)nPointSize, lpszFaceName);
	return Add((HFONT)ft.Detach());
}

CFontFactory* CFontFactory::Create(const CWnd&wnd, bool bold)
{
	do {
		CFont *ft = wnd.GetFont(); if (!ft) break;
		LOGFONT LogFont; if (!ft->GetLogFont(&LogFont)) break;
		LogFont.lfWeight = bold ? FW_BOLD : FW_NORMAL;
		return Add(::CreateFontIndirect(&LogFont));
	} while (0);
	return this;
}

CFontFactory* CFontFactory::Add(HFONT hFont)
{
	if (hFont)
	{
		if (m_Font) for (intptr_t i = 0; i < m_FontNum; i++) if (!m_Font[i])
		{
			m_lastFont = m_Font[i] = hFont; return this;
		}
		if ((m_FontNum & 0xf) == 0)
		{
			HFONT *tmp = (HFONT*)(m_Font ?
				HeapReAlloc(GetProcessHeap(), 0, m_Font, (m_FontNum + 16)*sizeof(HFONT)) :
				HeapAlloc(GetProcessHeap(), 0, (m_FontNum + 16)*sizeof(HFONT)));
			if (!tmp)
			{
				if (hFont) ::DeleteObject(hFont);
				return this;
			}
			m_Font = tmp;
		}
		m_lastFont = m_Font[m_FontNum++] = hFont;
	}
	return this;
}

CFontFactory* CFontFactory::AttachCtrl(CWnd &wnd, bool delOldFont)
{
	if (m_lastFont)
	{
		if (delOldFont && m_Font)
		{
			CFont *oldFont = wnd.GetFont(); if (oldFont) RemoveFont((HFONT)oldFont->GetSafeHandle());
		}
		wnd.SetFont(CFont::FromHandle(m_lastFont));
	}
	return this;
}

CFontFactory* CFontFactory::SetMark(FontMark mark)
{
	if (m_lastFont && mark != FM_UnMark)
	{
		intptr_t n = -1;
		if (m_Mark) for (intptr_t i = 0; i < m_MarkNum; i++) if (m_Mark[i].mark == mark)
		{
			if (m_Mark[i].hFont != m_lastFont) RemoveFont(m_Mark[i].hFont);
			n = i; break;
		}
		if (n < 0)
		{
			if ((m_MarkNum & 0xf) == 0)
			{
				stFontMark *tmp = (stFontMark*)(m_Mark ?
					HeapReAlloc(GetProcessHeap(), 0, m_Mark, (m_MarkNum + 16)*sizeof(stFontMark)) :
					HeapAlloc(GetProcessHeap(), 0, (m_MarkNum + 16)*sizeof(stFontMark)));
				if (!tmp) return this;
				m_Mark = tmp;
			}
			m_Mark[m_MarkNum].mark = mark; n = m_MarkNum++;
		}
		m_Mark[n].hFont = m_lastFont;
	}
	return this;
}

void CFontFactory::RemoveFont(HFONT oldFont)
{
	if (m_Font && oldFont) for (intptr_t i = 0; i < m_FontNum; i++) if (m_Font[i] == oldFont)
	{
		::DeleteObject(oldFont); m_Font[i] = nullptr; break;
	}
}
